﻿using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using log4net;

namespace KLY.Tools.Helper
{
    public static class AsyncHelper
    {
        /// <summary>
        /// Invoke Thread pool to execute method with async
        /// </summary>
        public static void Execute<T, F>(Func<T, F> action, Action<F> callBack, T state, string operationName = null)
        {
            if (action == null)
            {
                throw new ArgumentException("action");
            }

            ThreadPool.QueueUserWorkItem((obj) =>
            {
                DateTime startTime;
                F retF;

                startTime = DateTime.Now;
                retF = default(F);

                try
                {
                    retF = action(state);
                    if (callBack != null)
                    {
                        callBack(retF);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLogError("Error", ex);
                }
                finally
                {
                }
            });
        }

        /// <summary>
        /// Invoke async without returns
        /// </summary>
        public static void ExecuteAsync(Action action, Action callBack = null, string operationName = null)
        {
            if (action == null)
            {
                throw new ArgumentException("action");
            }

            Task.Factory.StartNew(() =>
            {
                Stopwatch sw;

                sw = new Stopwatch();

                try
                {
                    action();
                    if (callBack != null)
                    {
                        callBack();
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLogError("Error", ex);
                }
                finally
                {
                }
            });
        }

        /// <summary>
        /// Invoke async with task returns
        /// </summary>
        public static Task ExecuteAsyncRetrunTask(Action action, Action callBack = null, string operationName = null)
        {
            if (action == null)
            {
                throw new ArgumentException("action");
            }

            return Task.Factory.StartNew(() =>
            {
                Stopwatch sw;

                sw = new Stopwatch();

                try
                {
                    action();
                    if (callBack != null)
                    {
                        callBack();
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLogError("Error", ex);
                }
                finally
                {
                }
            });
        }

        /// <summary>
        /// Invoke task to execute method with async
        /// </summary>
        public static Task<R> ExecuteAsync<R>(Func<R> action, Action<R> callBack = null, R state = null, string operationName = null)
            where R : class
        {
            if (action == null)
            {
                throw new ArgumentException("action");
            }

            return Task.Factory.StartNew<R>(() =>
            {
                Stopwatch sw;
                R retR;

                sw = new Stopwatch();
                retR = default(R);

                try
                {
                    retR = action();
                    if (callBack != null)
                    {
                        callBack(retR);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLogError("Error", ex);
                }
                finally
                {
                    
                }
                return retR;
            });
        }

        /// <summary>
        /// Invoke task to execute method with struct returns
        /// </summary>
        public static Task<R> ExecuteStructAsync<R>(Func<R> action, string operationName = null)
            where R : struct
        {
            if (action == null)
            {
                throw new ArgumentException("action");
            }

            return Task.Factory.StartNew<R>(() =>
            {
                Stopwatch sw;
                R retR;

                sw = new Stopwatch();
                
                retR = default(R);
                try
                {
                    retR = action();
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLogError("Error", ex);
                }
                finally
                {
                }

                return retR;
            });
        }

        /// <summary>
        /// Invoke generic task to execute method
        /// </summary>
        public static Task<R> ExecuteAsync<T, R>(Func<T, R> action, Action<T> callBack = null, string operationName = null, T state = null)
            where R : class
            where T : class
        {
            if (action == null)
            {
                throw new ArgumentException("action");
            }

            return Task.Factory.StartNew<R>(() =>
            {
                Stopwatch sw;
                R retR;
                sw = new Stopwatch();
                retR = default(R);

                try
                {
                    retR = action(state);
                    if (callBack != null)
                    {
                        callBack(state);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLogError("Error", ex);
                }
                finally
                {
                }

                return retR;
            });
        }


        /// <summary>
        /// Invoke task without returns, but only return task
        /// </summary>
        public static Task ExecuteAsync<T, T2>(Action<T> action, Action<T> callBack = null, T state = null, string operationName = null)
            where T : class
        {
            if (action == null)
            {
                throw new ArgumentException("action");
            }

            return Task.Factory.StartNew(() =>
            {
                Stopwatch sw;

                sw = new Stopwatch();

                try
                {
                    action(state);
                    if (callBack != null)
                    {
                        callBack(state);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLogError("Error", ex);
                }
                finally
                {
                }
            });
        }
    }
}
